﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DWH.Configuration;
using System.Configuration;
using System.Reflection;
using System.Threading.Tasks;
using log4net;
using log4net.Config;
using System.IO;
using System.Xml;
using DWH.Utils;

namespace DWH.PP
{
    public class PPTaskExecutor
    {
        public string RDConfigFile { get; set; }

        protected List<PPTaskBase> ppTasks;
        protected List<Task> exeTasks;

        private ILog logger;

        public PPTaskExecutor()
        {            
            logger = LogManager.GetLogger(typeof(PPTaskExecutor));

            logger.Info("PPTaskExecutor constucted");
        }

        public void InitializeTasks()
        {
            List<RDTaskConfiguration> configs = null;

            if (String.IsNullOrEmpty(RDConfigFile))
            {
                logger.InfoFormat("RDConfigFile is not set, try to load from application configuration file");
                configs = (List<RDTaskConfiguration>)ConfigurationManager.GetSection("RDConfiguration");
                logger.InfoFormat("load RDTask,count:{0}",configs.Count);
            }
            else
            {
                logger.InfoFormat("load configuration from RDConfigFile {0}",RDConfigFile);
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(RDConfigFile);
                    configs = RDConfigurationHandler.LoadFromXmlNode(doc.DocumentElement);
                }
                catch (Exception ex)
                {
                    logger.ErrorFormat("error when reading RDConfigFile {0}, still try to load from app config, ex:{1}",RDConfigFile,ex.ToString());                    
                    configs = (List<RDTaskConfiguration>)ConfigurationManager.GetSection("RDConfiguration");
                }
            }
            ppTasks = new List<PPTaskBase>();
            exeTasks = new List<Task>();

            foreach (RDTaskConfiguration config in configs)
            {
                try
                {
                    PPTaskBase task = CreatePPTaskFromRDTaskConfiguration(config);

                    ppTasks.Add(task);
                }
                catch (Exception ex)
                {
                    logger.ErrorFormat("error when processing config item {0}, continue with other items, ex:{1}", config.TaskName, ex.ToString());  
                }
            }

            if (ppTasks == null || ppTasks.Count == 0)
            {
                logger.Error("no task was loaded, will exit");

                throw new ApplicationException("no task was loaded, will exit");
            }
        }

        public void StartTasks()
        {
            Task t;
            foreach (PPTaskBase task in ppTasks)
            {
                if (task.Enable)
                {
                    try
                    {
                        logger.InfoFormat("try to start task:{0}", task.TaskName);
                        t = Task.Factory.StartNew(task.Run);
                        exeTasks.Add(t);

                        DWHHelper.SimulateUserClickInterval(5);
                    }
                    catch (Exception ex)
                    {
                        logger.ErrorFormat("error occurs when trying to start task:{0}, {1}",task.TaskName,ex.ToString());
                    }
                }
            }
        }

        public void StopTasks()
        {
            foreach (Task t in exeTasks)
            {
                try
                {
                    t.Dispose();
                }
                catch (Exception ex)
                {
                    logger.ErrorFormat("error occures when trying to end task,{0}",ex.ToString());
                }
            }
        }

        public void ResetTasks()
        {
            logger.InfoFormat("try to reset all task, start over again");
            StopTasks();
            exeTasks.Clear();
            Task t;
            foreach (PPTaskBase task in ppTasks)
            {
                if (task.Enable)
                {
                    try
                    {
                        logger.InfoFormat("try to reset task:{0}", task.TaskName);
                        task.Reset();
                        t = Task.Factory.StartNew(task.Run);
                        exeTasks.Add(t);
                    }
                    catch (Exception ex)
                    {
                        logger.ErrorFormat("error occurs when trying to reset task:{0}, {1}", task.TaskName, ex.ToString());
                    }
                }
            }
        }

        public static PPTaskBase CreatePPTaskFromRDTaskConfiguration(RDTaskConfiguration config)
        {
            Assembly taskAsb = Assembly.LoadFrom(
                    Path.Combine(
                        Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                        config.AssemblyFile));
            Type taskType = taskAsb.GetType(config.TypeName);
            PPTaskBase task = (PPTaskBase)Activator.CreateInstance(taskType);

            task.Enable = config.Enable;
            task.TaskName = config.TaskName;
            task.ExtendData = config.ExtendData;

            task.Initialize();

            return task;
        }
    }
}
